/// @tags: SegmentTree BlockDiv
#include <algorithm>
#include <cstdio>
#include <iostream>

using namespace std;

namespace BlueQuantum {

typedef long long LL;

int const N = 1.5e5 + 5, B = 4e2, mod = 998244353, SIZ = B + 5;

int n, m, b_cnt, t_cnt;
int l[N], r[N], bel[N], fa[N];
int rt[SIZ], hash[SIZ][SIZ * 4];

struct Query {
  int opt, x, y, d;
} q[N];

struct Node {
  int ls, rs, add, mul, addt, mult;
  bool clear;
} tr[N * 4 * 2];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

inline int plus(int a, int b) {
  a += b;
  return a >= mod ? a - mod : a;
}

inline void pushdown(int x, int add, int mul, bool clear) {
  if (clear) {
    tr[x].mul = tr[x].mult = 1;
    tr[x].add = tr[x].addt = 0;
    tr[x].clear = true;
  }
  if (mul != 1) {
    tr[x].mul = (LL)tr[x].mul * mul % mod;
    tr[x].add = (LL)tr[x].add * mul % mod;
    tr[x].mult = (LL)tr[x].mult * mul % mod;
    tr[x].addt = (LL)tr[x].addt * mul % mod;
  }
  if (add) {
    tr[x].add = plus(tr[x].add, add);
    tr[x].addt = plus(tr[x].addt, add);
  }
}

inline void pushdown(int x) {
  pushdown(tr[x].ls, tr[x].addt, tr[x].mult, tr[x].clear);
  pushdown(tr[x].rs, tr[x].addt, tr[x].mult, tr[x].clear);
  tr[x].addt = 0, tr[x].mult = 1;
  tr[x].clear = false;
}

void build(int &x, int l, int r) {
  x = ++t_cnt;
  tr[x].mul = 1, tr[x].mult = 1;
  if (l == r) return;
  int mid = (l + r) >> 1;
  build(tr[x].ls, l, mid);
  build(tr[x].rs, mid + 1, r);
}

void modify(int x, int l, int r, int L, int R, int mul, int add) {
  if (L <= l && r <= R) { return pushdown(x, add, mul, false); }
  pushdown(x);
  int mid = (l + r) >> 1;
  if (L <= mid) modify(tr[x].ls, l, mid, L, R, mul, add);
  if (mid < R) modify(tr[x].rs, mid + 1, r, L, R, mul, add);
}

void query(int x, int l, int r, int p, int &val) {
  if (l == r) {
    val = plus((LL)val * tr[x].mul % mod, tr[x].add);
    return;
  }
  pushdown(x);
  int mid = (l + r) >> 1;
  return p <= mid ? query(tr[x].ls, l, mid, p, val) : query(tr[x].rs, mid + 1, r, p, val);
}

inline void prework() {
  b_cnt = (m - 1) / B + 1;
  for (int i = 1; i <= b_cnt; ++i) l[i] = r[i - 1] + 1, r[i] = l[i] + B - 1;
  r[b_cnt] = m;
  for (int i = 1; i <= m + 1; ++i) fa[i] = i;
  for (int i = 1; i <= b_cnt; ++i) {
    hash[i][++*hash[i]] = n;
    for (int j = l[i]; j <= r[i]; ++j) {
      bel[j] = i;
      if (q[j].opt <= 2) {
        hash[i][++*hash[i]] = q[j].x;
        hash[i][++*hash[i]] = q[j].x - 1;
        hash[i][++*hash[i]] = q[j].y;
        hash[i][++*hash[i]] = q[j].y - 1;
      }
    }
    sort(hash[i] + 1, hash[i] + *hash[i] + 1);
    *hash[i] = unique(hash[i] + 1, hash[i] + *hash[i] + 1) - hash[i] - 1;
    for (int j = l[i]; j <= r[i]; ++j)
      if (q[j].opt <= 2) {
        q[j].x = lower_bound(hash[i] + 1, hash[i] + *hash[i] + 1, q[j].x) - hash[i];
        q[j].y = lower_bound(hash[i] + 1, hash[i] + *hash[i] + 1, q[j].y) - hash[i];
      }
    build(rt[i], 1, *hash[i]);
  }
  for (int i = m; i >= 1; --i)
    if (q[i].opt > 2) fa[i] = find(i + 1);
}

inline int main() {
  cin >> n >> m;
  for (int i = 1; i <= m; ++i) {
    cin >> q[i].opt >> q[i].x;
    if (q[i].opt <= 2) cin >> q[i].y >> q[i].d;
    if (q[i].d >= mod) q[i].d -= mod;
  }
  prework();
  for (int i = 1; i <= m; ++i) {
    switch (q[i].opt) {
      case 1:
        modify(rt[bel[i]], 1, *hash[bel[i]], q[i].x, q[i].y, 1, q[i].d);
        break;
      case 2:
        modify(rt[bel[i]], 1, *hash[bel[i]], q[i].x, q[i].y, q[i].d, 0);
        break;
      case 3: {
        int p = q[i].x;
        int val = 0;
        for (int j = 1; j < bel[i]; ++j) {
          int pos = lower_bound(hash[j] + 1, hash[j] + *hash[j] + 1, p) - hash[j];
          query(rt[j], 1, *hash[j], pos, val);
        }
        int cur = find(l[bel[i]]);
        while (cur <= i) {
          int pos = lower_bound(hash[bel[i]] + 1, hash[bel[i]] + *hash[bel[i]] + 1, p) -
                    hash[bel[i]];
          if (q[cur].opt == 1 && q[cur].x <= pos && pos <= q[cur].y) {
            val = plus(val, q[cur].d);
          } else if (q[cur].opt == 2 && q[cur].x <= pos && pos <= q[cur].y)
            val = (LL)val * q[cur].d % mod;
          cur = find(cur + 1);
        }
        cout << val << '\n';
      } break;
      case 4: {
        int p = q[i].x;
        fa[p] = find(p + 1);
        pushdown(rt[bel[p]], 0, 1, true);
        int cur = find(l[bel[p]]);
        int tar = min(r[bel[p]], i);
        while (cur <= tar) {
          switch (q[cur].opt) {
            case 1:
              modify(rt[bel[p]], 1, *hash[bel[p]], q[cur].x, q[cur].y, 1, q[cur].d);
              break;
            case 2:
              modify(rt[bel[p]], 1, *hash[bel[p]], q[cur].x, q[cur].y, q[cur].d, 0);
          }
          cur = find(cur + 1);
        }
      }
    }
  }
  return 0;
}

}  // namespace BlueQuantum

int main() {
#ifndef ONLINE_JUDGE
#ifdef LOCAL
  freopen("/tmp/CodeTmp/testdata.in", "r", stdin);
  freopen("/tmp/CodeTmp/testdata.out", "w", stdout);
#else
  freopen("P3710 方方方的数据结构.in", "r", stdin);
  freopen("P3710 方方方的数据结构.out", "w", stdout);
#endif
#endif

  ios::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
  return BlueQuantum::main();
}
